// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"runtime/internal/atomic"
)

// 这是sync/rwmutex的副本。在运行时重新编写以工作。

// rwmutex是读写互斥锁。
// 锁可以由任意数量的读卡器或单个写卡器持有。这是sync的一个变种。RWMutex，用于运行时包。
// 与互斥体类似，rwmutex会阻止调用M。
// 它不会与goroutine调度程序交互。
type rwmutex struct {
	rLock      mutex    // 保护读者，读者群，writer 
	readers    muintptr // 待处理的读卡器列表
	readerPass uint32   // 待处理的跳过读卡器的数量

	wLock  mutex    // 序列化writer 
	writer muintptr // 待处理的写卡器等待完成读卡器

	readerCount uint32 // 待处理的读卡器数量
	readerWait  uint32 // 离开的读卡器数量
}

const rwmutexMaxReaders = 1 << 30

// R锁定rw以便读取。
func (rw *rwmutex) rlock() {
	// 不允许读卡器丢失其P或其他
	// 锁上阻塞的东西可能会消耗所有的P和
	// 死锁（问题#20903）。或者，我们可以在睡觉时放下P 
	// 。
	acquirem()
	if int32(atomic.Xadd(&rw.readerCount, 1)) < 0 {
		// 正在等待编写程序。把车停在读者队列上。
		systemstack(func() {
			lockWithRank(&rw.rLock, lockRankRwmutexR)
			if rw.readerPass > 0 {
				// 作者已完成。
				rw.readerPass -= 1
				unlock(&rw.rLock)
			} else {
				// 将此读者排队等待作者唤醒。
				m := getg().m
				m.schedlink = rw.readers
				rw.readers.set(m)
				unlock(&rw.rLock)
				notesleep(&m.park)
				noteclear(&m.park)
			}
		})
	}
}

// runlock撤销rw上的单个rlock调用。
func (rw *rwmutex) runlock() {
	if r := int32(atomic.Xadd(&rw.readerCount, -1)); r < 0 {
		if r+1 == 0 || r+1 == -rwmutexMaxReaders {
			throw("runlock of unlocked rwmutex")
		}
		// 正在等待编写程序。
		if atomic.Xadd(&rw.readerWait, -1) == 0 {
			// 最后一个读卡器将解锁写入器。
			lockWithRank(&rw.rLock, lockRankRwmutexR)
			w := rw.writer.ptr()
			if w != nil {
				notewakeup(&w.park)
			}
			unlock(&rw.rLock)
		}
	}
	releasem(getg().m)
}

// 为写入锁定rw。
func (rw *rwmutex) lock() {
	// 解决与其他作者的竞争问题，坚持我们的观点。
	lockWithRank(&rw.wLock, lockRankRwmutexW)
	m := getg().m
	// 宣布有一位作家悬而未决。
	r := int32(atomic.Xadd(&rw.readerCount, -rwmutexMaxReaders)) + rwmutexMaxReaders
	// 等待任何活动读卡器完成。
	lockWithRank(&rw.rLock, lockRankRwmutexR)
	if r != 0 && atomic.Xadd(&rw.readerWait, r) != 0 {
		// 等待读者唤醒我们。
		systemstack(func() {
			rw.writer.set(m)
			unlock(&rw.rLock)
			notesleep(&m.park)
			noteclear(&m.park)
		})
	} else {
		unlock(&rw.rLock)
	}
}

// 解锁可解锁rw进行写入。
func (rw *rwmutex) unlock() {
	// 向读者宣布，没有活跃的作家。
	r := int32(atomic.Xadd(&rw.readerCount, rwmutexMaxReaders))
	if r >= rwmutexMaxReaders {
		throw("unlock of unlocked rwmutex")
	}
	// 解除阻止被阻止的读卡器。
	lockWithRank(&rw.rLock, lockRankRwmutexR)
	for rw.readers.ptr() != nil {
		reader := rw.readers.ptr()
		rw.readers = reader.schedlink
		reader.schedlink.set(nil)
		notewakeup(&reader.park)
		r -= 1
	}
	// 如果r>0，则存在不在
	// 队列中的挂起读卡器。告诉他们不要等了。
	rw.readerPass += uint32(r)
	unlock(&rw.rLock)
	// 允许其他作者继续。
	unlock(&rw.wLock)
}
